<div class="content guide with-sidebar typescript-guide">
<h1>TypeScript 支持</h1>
<blockquote>
<p><a href="https://cli.vuejs.org/zh/" rel="noopener" target="_blank">Vue CLI</a> 内置了 TypeScript 工具支持。在 Vue 的下一个大版本 (3.x) 中也计划了相当多的 TypeScript 支持改进，包括内置的基于 class 的组件 API 和 TSX 的支持。</p>
</blockquote>
<h2 id="发布为-NPM-包的官方声明文件"><a class="headerlink" href="#发布为-NPM-包的官方声明文件" title="发布为 NPM 包的官方声明文件"></a>发布为 NPM 包的官方声明文件</h2><p>静态类型系统能帮助你有效防止许多潜在的运行时错误，而且随着你的应用日渐丰满会更加显著。这就是为什么 Vue 不仅仅为 Vue core 提供了针对 <a href="https://www.typescriptlang.org/" rel="noopener" target="_blank">TypeScript</a> 的<a href="https://github.com/vuejs/vue/tree/dev/types" rel="noopener" target="_blank">官方类型声明</a>，还为 <a href="https://github.com/vuejs/vue-router/tree/dev/types" rel="noopener" target="_blank">Vue Router</a> 和 <a href="https://github.com/vuejs/vuex/tree/dev/types" rel="noopener" target="_blank">Vuex</a> 也提供了相应的声明文件。</p>
<p>而且，我们已经把它们<a href="https://cdn.jsdelivr.net/npm/vue/types/" rel="noopener" target="_blank">发布到了 NPM</a>，最新版本的 TypeScript 也知道该如何自己从 NPM 包里解析类型声明。这意味着只要你成功地通过 NPM 安装了，就不再需要任何额外的工具辅助，即可在 Vue 中使用 TypeScript 了。</p>
<h2 id="推荐配置"><a class="headerlink" href="#推荐配置" title="推荐配置"></a>推荐配置</h2><pre><code class="hljs js"><span class="hljs-comment">// tsconfig.json</span>
{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-comment">// 与 Vue 的浏览器支持保持一致</span>
    <span class="hljs-string">"target"</span>: <span class="hljs-string">"es5"</span>,
    <span class="hljs-comment">// 这可以对 `this` 上的数据属性进行更严格的推断</span>
    <span class="hljs-string">"strict"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-comment">// 如果使用 webpack 2+ 或 rollup，可以利用 tree-shake:</span>
    <span class="hljs-string">"module"</span>: <span class="hljs-string">"es2015"</span>,
    <span class="hljs-string">"moduleResolution"</span>: <span class="hljs-string">"node"</span>
  }
}</code></pre>
<p>注意你需要引入 <code>strict: true</code> (或者至少 <code>noImplicitThis: true</code>，这是 <code>strict</code> 模式的一部分) 以利用组件方法中 <code>this</code> 的类型检查，否则它会始终被看作 <code>any</code> 类型。</p>
<p>参阅 <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html" rel="noopener" target="_blank">TypeScript 编译器选项文档 (英)</a> 了解更多。</p>
<h2 id="开发工具链"><a class="headerlink" href="#开发工具链" title="开发工具链"></a>开发工具链</h2><h3 id="工程创建"><a class="headerlink" href="#工程创建" title="工程创建"></a>工程创建</h3><p><a href="https://github.com/vuejs/vue-cli" rel="noopener" target="_blank">Vue CLI 3</a> 可以使用 TypeScript 生成新工程。创建方式：</p>
<pre><code class="hljs bash"><span class="hljs-comment"># 1. 如果没有安装 Vue CLI 就先安装</span>
npm install --global @vue/cli

<span class="hljs-comment"># 2. 创建一个新工程，并选择 "Manually select features (手动选择特性)" 选项</span>
vue create my-project-name</code></pre>
<h3 id="编辑器支持"><a class="headerlink" href="#编辑器支持" title="编辑器支持"></a>编辑器支持</h3><p>要使用 TypeScript 开发 Vue 应用程序，我们强烈建议您使用 <a href="https://code.visualstudio.com/" rel="noopener" target="_blank">Visual Studio Code</a>，它为 TypeScript 提供了极好的“开箱即用”支持。如果你正在使用<a href="./single-file-components.html">单文件组件</a> (SFC), 可以安装提供 SFC 支持以及其他更多实用功能的 <a href="https://github.com/vuejs/vetur" rel="noopener" target="_blank">Vetur 插件</a>。</p>
<p><a href="https://www.jetbrains.com/webstorm/" rel="noopener" target="_blank">WebStorm</a> 同样为 TypeScript 和 Vue 提供了“开箱即用”的支持。</p>
<h2 id="基本用法"><a class="headerlink" href="#基本用法" title="基本用法"></a>基本用法</h2><p>要让 TypeScript 正确推断 Vue 组件选项中的类型，您需要使用 <code>Vue.component</code> 或 <code>Vue.extend</code> 定义组件：</p>
<pre><code class="hljs ts"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">const</span> Component = Vue.extend({
  <span class="hljs-comment">// 类型推断已启用</span>
})

<span class="hljs-keyword">const</span> Component = {
  <span class="hljs-comment">// 这里不会有类型推断，</span>
  <span class="hljs-comment">// 因为TypeScript不能确认这是Vue组件的选项</span>
}</code></pre>
<h2 id="基于类的-Vue-组件"><a class="headerlink" href="#基于类的-Vue-组件" title="基于类的 Vue 组件"></a>基于类的 Vue 组件</h2><p>如果您在声明组件时更喜欢基于类的 API，则可以使用官方维护的 <a href="https://github.com/vuejs/vue-class-component" rel="noopener" target="_blank">vue-class-component</a> 装饰器：</p>
<pre><code class="hljs ts"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> Component <span class="hljs-keyword">from</span> <span class="hljs-string">'vue-class-component'</span>

<span class="hljs-comment">// @Component 修饰符注明了此类为一个 Vue 组件</span>
<span class="hljs-meta">@Component</span>({
  <span class="hljs-comment">// 所有的组件选项都可以放在这里</span>
  template: <span class="hljs-string">'&lt;button @click="onClick"&gt;Click!&lt;/button&gt;'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">class</span> MyComponent <span class="hljs-keyword">extends</span> Vue {
  <span class="hljs-comment">// 初始数据可以直接声明为实例的属性</span>
  message: <span class="hljs-built_in">string</span> = <span class="hljs-string">'Hello!'</span>

  <span class="hljs-comment">// 组件方法也可以直接声明为实例的方法</span>
  onClick (): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">window</span>.alert(<span class="hljs-keyword">this</span>.message)
  }
}</code></pre>
<h2 id="增强类型以配合插件使用"><a class="headerlink" href="#增强类型以配合插件使用" title="增强类型以配合插件使用"></a>增强类型以配合插件使用</h2><p>插件可以增加 Vue 的全局/实例属性和组件选项。在这些情况下，在 TypeScript 中制作插件需要类型声明。庆幸的是，TypeScript 有一个特性来补充现有的类型，叫做<a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation" rel="noopener" target="_blank">模块补充 (module augmentation)</a>。</p>
<p>例如，声明一个 <code>string</code> 类型的实例属性 <code>$myProperty</code>：</p>
<pre><code class="hljs ts"><span class="hljs-comment">// 1. 确保在声明补充的类型之前导入 'vue'</span>
<span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-comment">// 2. 定制一个文件，设置你想要补充的类型</span>
<span class="hljs-comment">//    在 types/vue.d.ts 里 Vue 有构造函数类型</span>
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> 'vue/types/vue' {
<span class="hljs-comment">// 3. 声明为 Vue 补充的东西</span>
  <span class="hljs-keyword">interface</span> Vue {
    $myProperty: <span class="hljs-built_in">string</span>
  }
}</code></pre>
<p>在你的项目中包含了上述作为声明文件的代码之后 (像 <code>my-property.d.ts</code>)，你就可以在 Vue 实例上使用 <code>$myProperty</code> 了。</p>
<pre><code class="hljs ts"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue()
<span class="hljs-built_in">console</span>.log(vm.$myProperty) <span class="hljs-comment">// 将会顺利编译通过</span></code></pre>
<p>你也可以声明额外的属性和组件选项：</p>
<pre><code class="hljs ts"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> 'vue/types/vue' {
  <span class="hljs-comment">// 可以使用 `VueConstructor` 接口</span>
  <span class="hljs-comment">// 来声明全局属性</span>
  <span class="hljs-keyword">interface</span> VueConstructor {
    $myGlobal: <span class="hljs-built_in">string</span>
  }
}

<span class="hljs-comment">// ComponentOptions 声明于 types/options.d.ts 之中</span>
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> 'vue/types/options' {
  <span class="hljs-keyword">interface</span> ComponentOptions&lt;V <span class="hljs-keyword">extends</span> Vue&gt; {
    myOption?: <span class="hljs-built_in">string</span>
  }
}</code></pre>
<p>上述的声明允许下面的代码顺利编译通过：</p>
<pre><code class="hljs ts"><span class="hljs-comment">// 全局属性</span>
<span class="hljs-built_in">console</span>.log(Vue.$myGlobal)

<span class="hljs-comment">// 额外的组件选项</span>
<span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
  myOption: <span class="hljs-string">'Hello'</span>
})</code></pre>
<h2 id="标注返回值"><a class="headerlink" href="#标注返回值" title="标注返回值"></a>标注返回值</h2><p>因为 Vue 的声明文件天生就具有循环性，TypeScript 可能在推断某个方法的类型的时候存在困难。因此，你可能需要在 <code>render</code> 或 <code>computed</code> 里的方法上标注返回值。</p>
<pre><code class="hljs ts"><span class="hljs-keyword">import</span> Vue, { VNode } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">const</span> Component = Vue.extend({
  data () {
    <span class="hljs-keyword">return</span> {
      msg: <span class="hljs-string">'Hello'</span>
    }
  },
  methods: {
    <span class="hljs-comment">// 需要标注有 `this` 参与运算的返回值类型</span>
    greet (): <span class="hljs-built_in">string</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.msg + <span class="hljs-string">' world'</span>
    }
  },
  computed: {
    <span class="hljs-comment">// 需要标注</span>
    greeting(): <span class="hljs-built_in">string</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.greet() + <span class="hljs-string">'!'</span>
    }
  },
  <span class="hljs-comment">// `createElement` 是可推导的，但是 `render` 需要返回值类型</span>
  render (createElement): VNode {
    <span class="hljs-keyword">return</span> createElement(<span class="hljs-string">'div'</span>, <span class="hljs-keyword">this</span>.greeting)
  }
})</code></pre>
<p>如果你发现类型推导或成员补齐不工作了，标注某个方法也许可以帮助你解决这个问题。使用 <code>--noImplicitAny</code> 选项将会帮助你找到这些未标注的方法。</p>
<div class="guide-links">
<span>← <a href="unit-testing.html">单元测试</a></span>
<span style="float: right;"><a href="deployment.html">生产环境部署</a> →</span>
</div>
<div class="footer">
<script src="//m.servedby-buysellads.com/monetization.js" type="text/javascript"></script>
<div class="bsa-cpc"></div>
<script>
  (function(){
    if(typeof _bsa !== 'undefined' && _bsa) {
    _bsa.init('default', 'CKYD62QM', 'placement:vuejsorg', {
      target: '.bsa-cpc',
      align: 'horizontal',
      disable_css: 'true'
    });
      }
  })();
</script>

    发现错误？想参与编辑？
    <a href="https://github.com/vuejs/cn.vuejs.org/blob/master/srctypescript.md" target="_blank">
      在 GitHub 上编辑此页！
    </a>
</div>
</div>